﻿// FILE           :Orb.cs
// PROJECT        :SETCritters                                        
// PROGRAMMER     :Kenneth Jinks and Ryan Pink                                         
// FIRST VERSION  :November 26 2013                                                
// DESCRIPTION    :
//      This file contains the class definition for the Orb object. It handles position and graphical
//      information for each orb, generates new graphical data upon initialization, and updates their 
//      position and velocity on request.

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing.Imaging;

namespace Orbs2Revengeance
{
    class Orb
    {
        private int mID;
        
        private Color mColour;
        private Point mPosition;
        private Point mVelocity;

        private int mScale;

        private Bitmap mOrbImg;
        private Bitmap mOrbShadow;


        #region ACCESSORS & MUTATORS

        public int ID
        {
            get
            {
                return mID;
            }
            set
            {
                mID = value;
            }
        }

        public Color Colour
        {
            get
            {
                return mColour;
            }
            set
            {
                mColour = value;
            }
        }


        public Point Position
        {
            get
            {
                return mPosition;
            }
            set
            {
                mPosition = value;
            }
        }


        public Point Velocity
        {
            get
            {
                return mVelocity;
            }
            set
            {
                mVelocity = value;
            }
        }


        public int Scale
        {
            get
            {
                return mScale;
            }
            set
            {
                mScale = value;
            }
        }


        public Image OrbImg
        {
            get
            {
                return mOrbImg;
            }
        }


        public Image OrbShadow
        {
            get
            {
                return mOrbShadow;
            }
        }

        #endregion


        #region CONSTRUCTORS

        public Orb()
        {
            mID = 0;
            mColour = Color.Green;

            Random r = new Random(DateTime.Now.Millisecond);

            mPosition = new Point(r.Next(0, 1336), r.Next(0, 768));
            mVelocity = new Point(r.Next(0, 3), r.Next(0, 3));

            mScale = 64;

            mOrbImg = new Bitmap(mScale, mScale, PixelFormat.Format32bppArgb);

            GenerateImages();
        }


        public Orb(Color _colour, int _scale)
        {
            mID = 0;
            mColour = _colour;

            Random r = new Random(DateTime.Now.Millisecond);

            mPosition = new Point();
            mVelocity = new Point();

            //mPosition = new Point(r.Next(0, 1336), r.Next(0, 768));
            //mVelocity = new Point(r.Next(0, 3), r.Next(0, 3));

            mScale = _scale;

            mOrbImg = new Bitmap(mScale, mScale, PixelFormat.Format32bppArgb);
            mOrbShadow = new Bitmap(mScale, mScale, PixelFormat.Format32bppArgb);

            GenerateImages();
        }

        #endregion


        #region METHODS
        
        /// <summary>
        ///     This method is called when an Orb is instantiated, and it draws out a new orb
        ///     graphic given the colour input by the user (or code). It also generates a gradient
        ///     image to be used to draw the trail.
        /// </summary>
        private void GenerateImages()
        {
            Graphics gOrb = Graphics.FromImage(mOrbImg);
            Graphics gShadow = Graphics.FromImage(mOrbShadow);
            byte alpha = 0;

            for (int i = 0; i < mScale / 2; ++i)
            {
                gOrb.FillEllipse(new SolidBrush(Color.Transparent), i, i, mScale - 2 * i, mScale - 2 * i);
                gOrb.FillEllipse(new SolidBrush(Color.FromArgb(alpha, mColour)), i, i, mScale - 2 * i, mScale - 2 * i);

                alpha += (byte)(128 / mScale);
            }

            alpha = 0;

            for (int i = mScale / 6; i < mScale / 2; ++i)
            {
                gOrb.FillEllipse(new SolidBrush(Color.FromArgb(alpha, Color.White)), i, i, mScale - 2 * i, mScale - 2 * i);
                gShadow.FillEllipse(new SolidBrush(Color.FromArgb(alpha, mColour)), i, i, mScale - 2 * i, mScale - 2 * i);

                alpha += (byte)(128 / mScale);
            }
        }

        /// <summary>
        ///     This function is called every game loop in the Reshape() method. It applies a random
        ///     wobble to the idle and auto Orbs' velocities and assigns their new positions.
        ///     If the orb leaves one end of the screen, it will be repositioned on the other side.
        /// </summary>
        internal void Update()
        {
            if (mID != 0)
            {
                Random r = new Random(Math.Abs(mPosition.X + mPosition.Y));
                int wobbleX = (int)(Math.Sin(DateTime.Now.Millisecond + r.Next()) - Math.Cos(DateTime.Now.Millisecond + r.Next()));
                int wobbleY = (int)(Math.Cos(DateTime.Now.Millisecond + r.Next()) - Math.Sin(DateTime.Now.Millisecond + r.Next()));

                if (mVelocity.X + wobbleX > -8 && mVelocity.X + wobbleX < 8)
                {
                    mVelocity.X += wobbleX;
                }
                else
                {
                    mVelocity.X -= wobbleX;
                }

                if (mVelocity.Y + wobbleY > -8 && mVelocity.Y + wobbleY < 8)
                {
                    mVelocity.Y += wobbleY;
                }
                else
                {
                    mVelocity.Y -= wobbleY;
                }
            }

            mPosition.X += mVelocity.X;
            mPosition.Y += mVelocity.Y;

            if (mPosition.X < -mScale)
            {
                mPosition.X = 1300 + mScale;
            }
            else if (mPosition.X > 1300 + mScale)
            {
                mPosition.X = 0 - mScale;
            }

            if (mPosition.Y < 0 - mScale)
            {
                mPosition.Y = 700 + mScale;
            }
            else if (mPosition.Y > 700 + mScale)
            {
                mPosition.Y = 0 - mScale;
            }
        }
        
        #endregion
    }
}
